/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.qiujuer.sample.genius.bar;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.LayoutScatter;
import ohos.agp.components.Text;
import ohos.agp.components.element.Element;
import ohos.agp.utils.Color;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.utils.Rect;
import ohos.agp.window.dialog.PopupDialog;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.miscservices.timeutility.Time;

import net.qiujuer.genius.ui.element.RipAnimElement;
import net.qiujuer.genius.ui.element.RipElement;
import net.qiujuer.sample.genius.ResourceTable;

/**
 * Toolbar
 *
 * @since 2021-05-10
 */
public class Toolbar extends ComponentContainer implements RipElement.RipCallback {
    private EventHandler mEventHandler = new EventHandler(EventRunner.getMainEventRunner());
    private Rect mRect = new Rect();
    private Text mTitleText;
    private DirectionalLayout mDlMenu;
    private OnMenuItemClickListener mOnMenuItemClickListener;
    private DrawTask mDrawTask = (component, canvas) -> {
        if (mRect.isEmpty()) {
            RipAnimElement ripAnim = new RipAnimElement();
            ripAnim.setColor(Color.getIntColor("#FF6200EE"));
            ripAnim.setFluCount(0, 0, 0, 36);
            component.getSelfVisibleRect(mRect);
            ripAnim.setBounds(mRect);
            component.setBackground(ripAnim);
        }
        RipElement element = (RipElement) getBackgroundElement();
        if (element != null) {
            element.setRipCallback(Toolbar.this);
            element.draw(canvas);
        }
    };

    /**
     * constructor
     *
     * @param context
     */
    public Toolbar(Context context) {
        super(context);
        addDrawTask(mDrawTask, DrawTask.BETWEEN_BACKGROUND_AND_CONTENT);
        inflate();
    }

    /**
     * constructor
     *
     * @param context
     * @param attrSet
     */
    public Toolbar(Context context, AttrSet attrSet) {
        super(context, attrSet);
        addDrawTask(mDrawTask, DrawTask.BETWEEN_BACKGROUND_AND_CONTENT);
        inflate();
    }

    /**
     * constructor
     *
     * @param context
     * @param attrSet
     * @param styleName
     */
    public Toolbar(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        addDrawTask(mDrawTask, DrawTask.BETWEEN_BACKGROUND_AND_CONTENT);
        inflate();
    }

    private void inflate() {
        LayoutScatter.getInstance(getContext()).parse(ResourceTable.Layout_layout_toolbar, this, true);
        mTitleText = (Text) findComponentById(ResourceTable.Id_txt_title);
        mDlMenu = (DirectionalLayout) findComponentById(ResourceTable.Id_dl_menu);
    }

    /**
     * create menu in this toolbar
     */
    public void createMenu() {
        mDlMenu.setVisibility(Component.VISIBLE);
        mDlMenu.setClickedListener(c -> {
            showMenu();
        });
    }

    private void showMenu() {
        Component component = LayoutScatter.getInstance(getContext())
            .parse(ResourceTable.Layout_menu_pop_layout, null, false);
        PopupDialog popupDialog = new PopupDialog(getContext(), null);
        popupDialog.setCustomComponent(component);
        popupDialog.setDialogListener(() -> {
            popupDialog.destroy();
            return false;
        });
        component.setClickedListener(component2 -> {
            popupDialog.destroy();
        });
        final Text txtBlur = (Text) component.findComponentById(ResourceTable.Id_action_blur);
        final Text txtBlurClip = (Text) component.findComponentById(ResourceTable.Id_action_blur_clip);
        final Text txtKit = (Text) component.findComponentById(ResourceTable.Id_action_kit);
        final Text txtSeekBar = (Text) component.findComponentById(ResourceTable.Id_action_seekBar);
        txtBlur.setClickedListener(component1 -> {
            popupDialog.destroy();
            if (mOnMenuItemClickListener != null) {
                mOnMenuItemClickListener.onMenuItemClick(txtBlur);
            }
        });
        txtBlurClip.setClickedListener(component1 -> {
            popupDialog.destroy();
            if (mOnMenuItemClickListener != null) {
                mOnMenuItemClickListener.onMenuItemClick(txtBlurClip);
            }
        });
        txtKit.setClickedListener(component1 -> {
            popupDialog.destroy();
            if (mOnMenuItemClickListener != null) {
                mOnMenuItemClickListener.onMenuItemClick(txtKit);
            }
        });
        txtSeekBar.setClickedListener(component1 -> {
            popupDialog.destroy();
            if (mOnMenuItemClickListener != null) {
                mOnMenuItemClickListener.onMenuItemClick(txtSeekBar);
            }
        });
        int[] position = getLocationOnScreen();
        int x = getWidth() - component.getWidth();
        int y = position[1];
        popupDialog.showOnCertainPosition(LayoutAlignment.TOP, x, y);
    }

    /**
     * set OnMenuItemClickListener
     *
     * @param onMenuItemClickListener
     */
    public void setOnMenuItemClickListener(OnMenuItemClickListener onMenuItemClickListener) {
        this.mOnMenuItemClickListener = onMenuItemClickListener;
    }

    /**
     * set title
     *
     * @param title
     */
    public void setTitle(String title) {
        if (mTitleText != null) {
            mTitleText.setText(title);
        }
    }

    /**
     * Invalidates the specified Drawable.
     *
     * @param drawable the drawable to invalidate
     */
    @Override
    public void invalidateDrawable(RipElement drawable) {
        if (verifyDrawable(drawable)) {
            invalidate();
        }
    }

    /**
     * Schedules an action on a drawable to occur at a specified time.
     *
     * @param who the recipient of the action
     * @param what the action to run on the drawable
     * @param when the time at which the action must occur. Uses the
     *        {@link Time#getRealActiveTime()} timebase.
     */
    @Override
    public void scheduleDrawable(RipElement who, Runnable what, long when) {
        final long delay = when - Time.getRealActiveTime();
        mEventHandler.postTask(what, delay, EventHandler.Priority.IMMEDIATE);
    }

    /**
     * Cancels a scheduled action on a drawable.
     *
     * @param who the recipient of the action
     * @param what the action to cancel
     */
    @Override
    public void unscheduleDrawable(RipElement who, Runnable what) {
        mEventHandler.removeTask(what);
    }

    /**
     * If your view subclass is displaying its own Drawable objects, it should
     * override this function and return true for any Drawable it is
     * displaying. This allows animations for those drawables to be
     * scheduled.
     *
     * @param who
     * @return boolean If true than the Drawable is being displayed in the
     * view; else false and it is not allowed to animate.
     */
    protected boolean verifyDrawable(Element who) {
        // Avoid verifying the scroll bar drawable so that we don't end up in
        // an invalidation loop. This effectively prevents the scroll bar
        // drawable from triggering invalidations and scheduling runnables.
        return who == getBackgroundElement() || (getForegroundElement() != null && getForegroundElement() == who);
    }

    /**
     * OnMenuItemClickListener
     *
     * @since 2021-05-12
     */
    public interface OnMenuItemClickListener {
        /**
         * This method will be invoked when a menu item is clicked if the item itself did
         * not already handle the event.
         *
         * @param item that was clicked
         * @return <code>true</code> if the event was handled, <code>false</code> otherwise.
         */
        boolean onMenuItemClick(Text item);
    }
}
